package com.ccrfid.rmc6.service.alarm;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.alarm.AlarmLocationTypeEntity;
import com.ccrfid.rmc6.entity.alarm.AlarmRuleEntity;
import com.ccrfid.rmc6.entity.alarm.AlarmRuleTemplateEntity;
import com.ccrfid.rmc6.entity.poi.PoiLocationEntity;
import com.ccrfid.rmc6.entity.sys.DictEntity;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.pojo.dto.LocationAlarmRuleDto;
import com.ccrfid.rmc6.pojo.dto.alarm.AlarmRuleDto;
import com.ccrfid.rmc6.pojo.dto.report.DayAlarmCountDto;
import com.ccrfid.rmc6.repository.alarm.AlarmLocationTypeRepository;
import com.ccrfid.rmc6.repository.alarm.AlarmRuleRepository;
import com.ccrfid.rmc6.repository.alarm.AlarmRuleTemplateRepository;
import com.ccrfid.rmc6.repository.poi.PoiLocationRepository;
import com.ccrfid.rmc6.repository.search.SearchCriteria;
import com.ccrfid.rmc6.repository.sys.DictRepository;
import com.ccrfid.rmc6.util.DateUtil;
import org.hibernate.query.NativeQuery;
import org.hibernate.transform.Transformers;
import org.hibernate.type.IntegerType;
import org.hibernate.type.StringType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.sql.Timestamp;
import java.util.*;

@Service
@Transactional
public class AlarmRuleServiceImpl implements AlarmRuleService {
    private static final Logger logger = LoggerFactory.getLogger(AlarmRuleServiceImpl.class);
    @Autowired
    private PoiLocationRepository poiLocationRepository;
    @Autowired
    private AlarmRuleRepository alarmRuleRepository;
    @Autowired
    private AlarmLocationTypeRepository alarmLocationTypeRepository;
    @Autowired
    private AlarmRuleTemplateRepository alarmRuleTemplateRepository;
    @Autowired
    private DictRepository dictRepository;
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Set<Long> getLocationIdList(List<Integer> alarmTypeList, Integer alarmStatus) {
        if (alarmStatus != null) {
            if (alarmStatus.equals(0)) {
                //未布防的区域
                if (alarmTypeList != null && alarmTypeList.size() > 0) {
                    //某类未布防的区域
                    List<AlarmRuleEntity> list = alarmRuleRepository.getAllByAlarmTypeIn(alarmTypeList);
                    Set<Long> alarmLocationIdSet = new HashSet<>();
                    for (AlarmRuleEntity alarmRuleEntity : list) {
                        alarmLocationIdSet.add(alarmRuleEntity.getLocationId());
                    }
                    if (alarmLocationIdSet.size() > 0) {
                        return alarmLocationIdSet;  //返回某类布防的区域
                    } else {
                        return null;                //返回全部区域
                    }
                } else {
                    //全部未布防的区域
                    List<AlarmRuleEntity> list = alarmRuleRepository.getAllBy();
                    Set<Long> alarmLocationIdSet = new HashSet<>();
                    for (AlarmRuleEntity alarmRuleEntity : list) {
                        alarmLocationIdSet.add(alarmRuleEntity.getLocationId());
                    }
                    if (alarmLocationIdSet.size() > 0) {
                        return alarmLocationIdSet;      //返回全部布防的区域
                    } else {
                        return null;                    //返回全部区域
                    }
                }
            } else if (alarmStatus.equals(1)) {
                //布防的区域
                if (alarmTypeList != null && alarmTypeList.size() > 0) {
                    //某类布防的区域
                    List<AlarmRuleEntity> list = alarmRuleRepository.getAllByAlarmTypeIn(alarmTypeList);
                    Set<Long> locationIdSet = new HashSet<>();
                    for (AlarmRuleEntity alarmRuleEntity : list) {
                        locationIdSet.add(alarmRuleEntity.getLocationId());
                    }
                    return locationIdSet;
                } else {
                    //全部布防的区域
                    List<AlarmRuleEntity> list = alarmRuleRepository.getAllBy();
                    Set<Long> locationIdSet = new HashSet<>();
                    for (AlarmRuleEntity alarmRuleEntity : list) {
                        locationIdSet.add(alarmRuleEntity.getLocationId());
                    }
                    return locationIdSet;
                }
            }
        } else {
            if (alarmTypeList != null && alarmTypeList.size() > 0) {
                //某类布防的区域
                List<AlarmRuleEntity> list = alarmRuleRepository.getAllByAlarmTypeIn(alarmTypeList);
                Set<Long> locationIdSet = new HashSet<>();
                for (AlarmRuleEntity alarmRuleEntity : list) {
                    locationIdSet.add(alarmRuleEntity.getLocationId());
                }
                return locationIdSet;
            } else {
                //全部区域
                return null;
            }
        }
        return null;
    }

    @Override
    public Page<LocationAlarmRuleDto> getAlarmLocations(SearchCriteria criteria, Pageable pageable) {
        Page<PoiLocationEntity> locationPage = poiLocationRepository.search(criteria, pageable);
        List<LocationAlarmRuleDto> dtoList = new ArrayList<>();
        List<PoiLocationEntity> locationList = locationPage.getContent();
        if (locationList != null && locationList.size() > 0) {
            for (PoiLocationEntity locationEntity : locationList) {
                LocationAlarmRuleDto dto = new LocationAlarmRuleDto();
                dto.setLocation(locationEntity);
                dto.setAlarmRules(getAlarmRulesByLocationId(locationEntity.getId()));
                dtoList.add(dto);
            }
        }
        PageImpl<LocationAlarmRuleDto> resultPage = new PageImpl<>(dtoList, pageable, locationPage.getTotalElements());
        return resultPage;
    }

    @Override
    public List<AlarmRuleEntity> getAlarmRulesByLocationId(Long locationId) {
        return alarmRuleRepository.getAllByLocationId(locationId);
    }

    @Override
    public LocationAlarmRuleDto getLocationAlarmRules(Long locationId) {
        PoiLocationEntity locationEntity = poiLocationRepository.getById(locationId);
        if (locationEntity != null) {
            LocationAlarmRuleDto dto = new LocationAlarmRuleDto();
            dto.setLocation(locationEntity);
            dto.setAlarmRules(getAlarmRulesByLocationId(locationId));
            return dto;
        }
        return null;
    }

    @Override
    public List<AlarmLocationTypeEntity> getLocationAlarmTypes(Integer locationType) {
        if (alarmLocationTypeRepository.existsByLocationType(locationType)) {
            return alarmLocationTypeRepository.getAllByLocationType(locationType);
        } else {
            return alarmLocationTypeRepository.getAllByLocationType(0); //0-取默认值
        }
    }

    @Override
    public AlarmRuleEntity getAlarmRule(Long alarmRuleId) {
        return alarmRuleRepository.getById(alarmRuleId);
    }

    @Override
    public AlarmRuleEntity createAlarmRule(AlarmRuleEntity entity) throws AppException {
        if (entity.getAlarmType().equals(Constants.ALARM_TYPE.MUTUAL_ALARM.id)) {
            //互监告警区域设置为空
            entity.setLocationId(0L);
        } else {
            if (entity.getLocationId() == null || !poiLocationRepository.existsById(entity.getLocationId())) {
                throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                        CustomErrors.location_not_found.getCode(), CustomErrors.location_not_found.getReason(), "");
            }
        }
        return alarmRuleRepository.save(entity);
    }

    @Override
    public List<AlarmRuleEntity> batchCreateAlarmRules2LocationType(Integer locationType, AlarmRuleEntity entity) {
        List<AlarmRuleEntity> resultList = new ArrayList<>();
        List<PoiLocationEntity> locationList =
                poiLocationRepository.getAllByLocationTypeAndMapLevel(locationType, Constants.MAP_LEVEL.THREE.id);
        if (locationList != null && locationList.size() > 0) {
            for (PoiLocationEntity locationEntity : locationList) {
                AlarmRuleEntity alarmRuleEntity = new AlarmRuleEntity();
                alarmRuleEntity.setAlarmRuleName(entity.getAlarmRuleName());
                alarmRuleEntity.setLocationId(locationEntity.getId());
                alarmRuleEntity.setRelatedLocations(entity.getRelatedLocations());
                alarmRuleEntity.setAlarmType(entity.getAlarmType());
                alarmRuleEntity.setPersonnelValue(entity.getPersonnelValue());
                alarmRuleEntity.setPersonnelValue2(entity.getPersonnelValue2());
                alarmRuleEntity.setTimeType(entity.getTimeType());
                alarmRuleEntity.setTimeValue(entity.getTimeValue());
                alarmRuleEntity.setDelayTime(entity.getDelayTime());
                alarmRuleEntity.setAlarmLevel(entity.getAlarmLevel());
                alarmRuleEntity.setAlarmLinkageMode(entity.getAlarmLinkageMode());
                alarmRuleEntity = alarmRuleRepository.save(alarmRuleEntity);
                resultList.add(alarmRuleEntity);
            }
        }
        return resultList;
    }

    @Override
    public AlarmRuleEntity updateAlarmRule(Long alarmRuleId, AlarmRuleEntity entity) throws AppException {
        if (!alarmRuleRepository.existsById(alarmRuleId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (!alarmRuleId.equals(entity.getId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        if (entity.getAlarmType().equals(Constants.ALARM_TYPE.MUTUAL_ALARM.id)) {
            //互监告警区域设置为空
            entity.setLocationId(0L);
        } else {
            if (entity.getLocationId() == null || !poiLocationRepository.existsById(entity.getLocationId())) {
                throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                        CustomErrors.location_not_found.getCode(), CustomErrors.location_not_found.getReason(), "");
            }
        }
        return alarmRuleRepository.save(entity);
    }

    @Override
    public Boolean deleteAlarmRule(Long alarmRuleId) throws AppException {
        if (!alarmRuleRepository.existsById(alarmRuleId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        alarmRuleRepository.deleteById(alarmRuleId);
        return true;
    }

    @Override
    public List<AlarmRuleTemplateEntity> getAlarmRuleTemplates(SearchCriteria criteria, Sort sort) {
        return alarmRuleTemplateRepository.search(criteria, sort);
    }

    @Override
    public AlarmRuleTemplateEntity getAlarmRuleTemplate(Long templateId) {
        return alarmRuleTemplateRepository.getById(templateId);
    }

    @Override
    public AlarmRuleTemplateEntity createAlarmRuleTemplate(AlarmRuleTemplateEntity entity) {
        return alarmRuleTemplateRepository.save(entity);
    }

    @Override
    public AlarmRuleTemplateEntity updateAlarmRuleTemplate(Long templateId, AlarmRuleTemplateEntity entity)
            throws AppException {
        if (!alarmRuleTemplateRepository.existsById(templateId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (!templateId.equals(entity.getId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        return alarmRuleTemplateRepository.save(entity);
    }

    @Override
    public Boolean deleteAlarmRuleTemplate(Long templateId) throws AppException {
        if (!alarmRuleTemplateRepository.existsById(templateId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        alarmRuleTemplateRepository.deleteById(templateId);
        return true;
    }

    @Override
    public String getAlarmRuleTypeName(Integer alarmRuleType) {
        DictEntity dictEntity = dictRepository.getById(alarmRuleType);
        if (dictEntity != null) {
            return dictEntity.getDictName();
        }
        return "";
    }

    @Override
    public List<AlarmRuleEntity> getAllAlarmRules() {
        return alarmRuleRepository.getAllBy();
    }

    @Override
    public List<AlarmRuleEntity> getMutualAlarmRuleList() {
        return alarmRuleRepository.getAllByAlarmType(Constants.ALARM_TYPE.MUTUAL_ALARM.id);
    }

    @Override
    public List<String> getAllAlarmRuleName() {
        return alarmRuleRepository.getDistinctByAlarmRuleName();
    }

    @Override
    public List<AlarmRuleDto> getAlarmRuleForApp() {
        List<AlarmRuleEntity> alarmRuleEntityList = alarmRuleRepository.getAllByAlarmType(440);
        List<AlarmRuleEntity> resultList = new ArrayList<>();
        for(AlarmRuleEntity alarmRuleEntity : alarmRuleEntityList){
            String timeValueList = alarmRuleEntity.getTimeValue();
            JSONArray timeValueArray = JSONArray.parseArray(timeValueList);
            for(int i =0; i < timeValueArray.size(); i++){
                JSONObject value = timeValueArray.getJSONObject(i);
//                Date startTime  = DateUtil.parseDateTimeStr(value.getString("startTime"));
                Date stopTime  = DateUtil.parseDateTimeStr(value.getString("stopTime"));
                if(stopTime.after(new Date())){
                    resultList.add(alarmRuleEntity);
                    break;
                }
            }
        }

        List<AlarmRuleDto> alarmRuleDtoList = new ArrayList<>();
        for(AlarmRuleEntity alarmRuleEntity : resultList){
            AlarmRuleDto alarmRuleDto = new AlarmRuleDto();
            alarmRuleDto.setId(alarmRuleEntity.getId());
            alarmRuleDto.setAlarmLevel(alarmRuleEntity.getAlarmLevel());
            alarmRuleDto.setAlarmLinkageMode(alarmRuleEntity.getAlarmLinkageMode());
            alarmRuleDto.setAlarmRuleName(alarmRuleEntity.getAlarmRuleName());
            alarmRuleDto.setAlarmType(alarmRuleEntity.getAlarmType());
            alarmRuleDto.setDelayTime(alarmRuleEntity.getDelayTime());
            alarmRuleDto.setLocationId(alarmRuleEntity.getLocationId());
            alarmRuleDto.setPersonnelValue(alarmRuleEntity.getPersonnelValue());
            alarmRuleDto.setPersonnelValue2(alarmRuleEntity.getPersonnelValue2());
            alarmRuleDto.setRelatedLocations(alarmRuleEntity.getRelatedLocations());
            alarmRuleDto.setTimeType(alarmRuleEntity.getTimeType());
            alarmRuleDto.setTimeValue(alarmRuleEntity.getTimeValue());
            PoiLocationEntity poiLocationEntity = poiLocationRepository.getById(alarmRuleDto.getLocationId());
            alarmRuleDto.setLocationName(poiLocationEntity.getLocationName());
            alarmRuleDtoList.add(alarmRuleDto);
        }
        return alarmRuleDtoList;
    }

    @Override
    public Boolean batchDeleteAlarmRule(List<Long> alarmRuleIdList) throws AppException {
        for(Long alarmRuleId : alarmRuleIdList){
            if (!alarmRuleRepository.existsById(alarmRuleId)) {
                throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                        CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
            }
            alarmRuleRepository.deleteById(alarmRuleId);
        }
        return true;
    }
}
